package com.example.gokuplayalong.bases.network.security;

import static java.lang.Math.abs;

import android.content.Context;

import com.example.gokuplayalong.MainActivity;
import com.example.gokuplayalong.bases.exception.ExceptionUtils;
import com.example.gokuplayalong.bases.tools.Tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Base64;
import java.util.Objects;

public class Communication {
    private final int VALID_TIME_MAX = 1000 * 3600;
    public int code = 0;
    private String AesKey = "";
    private String RSAAesKey = "";
    private String AESMsg = "";
    private String TimeStamp = "";
    public static String md5Key = "";
    private String md5rand = "";
    private String md5Sign = "";


    static Communication INSTANCE;

    public static Communication getInstance() {
        if (INSTANCE == null) INSTANCE = new Communication();
        return INSTANCE;
    }

    public String MessageEncrypt(String message) {
        try {
            md5Key = MD5Keys.getInstance().getKey();
            //1.生成AES密钥
            if (AesKey == null || AesKey.equals("")) {
                AesKey = AESEncrypt.getKey();
            }
            //2.使用ServerRSA公钥 对AES密钥进行加密
            RSAAesKey = RSAEncrypt.encryptByPublicKey(AesKey, RSAEncrypt.ServerPublicKey);
            //3.使用AES密钥对消息明文进行加密
            AESMsg = AESEncrypt.encrypt(message, AesKey);
            //4.获取当前时间戳
            TimeStamp = String.valueOf(System.currentTimeMillis());
            //5.生成随机字符串
            md5rand = AESEncrypt.getKey();
            //6.将参数密文、时间戳、随机字符串和AES密钥密文进行MD5计算得到md5值；
            //AESMsg TimeStamp md5rand RSAesKey md5Key
            String md5in = RSAAesKey + "." + AESMsg + "." + TimeStamp + "." + md5rand;
            //7.计算MD5的数字签名
            String md5 = MD5Util.string2MD5(md5in + md5Key);
            md5Sign = RSAEncrypt.sign(md5.getBytes(), Base64.getDecoder().decode(Keys.getInstance().getKey()), "RSA");
            //8.拼接结果
            if (RSAAesKey == null || AESMsg == null || TimeStamp == null || md5rand == null || md5Sign == null) {
                code = 4;
                return "空值，无效参数";
            }
            return md5in + "." + md5Sign;
        } catch (Exception e) {
            ExceptionUtils.getException(Tools.getTraceInfo(), e);
            return "";
        }
    }

    public String MessageDecrypt(String message) {
        try {
            md5Key = MD5Keys.getInstance().getKey();
            code = 0;
            String[] str = message.split("\\.");
            //将服务器发来的字符串赋值给各个字段
            if (str.length != 5) {
                code = -1;
                return "无效请求";
            }
            RSAAesKey = str[0];
            AESMsg = str[1];
            TimeStamp = str[2];
            md5rand = str[3];
            md5Sign = str[4];
            //1.验证时间有效性
            if (abs(System.currentTimeMillis() - Long.parseLong(TimeStamp)) > VALID_TIME_MAX) {
                code = 1;
                return "无效请求";
            }
            //2.验证md5rand唯一性
            File f = new File(MainActivity.getInstance().getFilesDir().getAbsoluteFile() + "/md5rand");
            if (!f.exists()) {
                f.createNewFile();
            }
            if (f.exists()) {

                FileInputStream in = MainActivity.getInstance().openFileInput("md5rand");
                byte[] buffer = new byte[in.available()];//创建byte数组用于读入数据
                in.read(buffer);
                in.close();
                String md5randin = new String(buffer);
                String[] md5randList = md5randin.split("\\.");

                for (String s : md5randList) {
                    if (Objects.equals(s, md5rand)) {
                        code = 2;
                        return "无效请求";
                    }
                }
                FileOutputStream out;
                if (md5randList.length > 1000) {
                    out = MainActivity.getInstance().openFileOutput("md5rand", Context.MODE_PRIVATE);

                }
                else {
                    out = MainActivity.getInstance().openFileOutput("md5rand", Context.MODE_APPEND);
                }
                out.write((md5rand + ".").getBytes());
                out.close();
            }
            //3.验证签名有效性
            String md5in = RSAAesKey + "." + AESMsg + "." + TimeStamp + "." + md5rand;
            String md5 = MD5Util.string2MD5(md5in + md5Key);
            //服务器公钥验签
            boolean verify = RSAEncrypt.verify(md5.getBytes(), Base64.getDecoder().decode(md5Sign.replaceAll("\r|\n", "")), Base64.getDecoder().decode(RSAEncrypt.ServerPublicKey), "RSA");
            if (!verify) {
                code = 3;
                return "无效请求";
            }
            //4.APP解密AES密钥密文
            AesKey = RSAEncrypt.decryptByPrivateKey(RSAAesKey, Keys.getInstance().getKey());
            //5.解密参数密文
            AESMsg = AESEncrypt.decrypt(AESMsg, AesKey);

        } catch (Throwable e) {
            ExceptionUtils.getException(Tools.getTraceInfo(), e);
        }
        return AESMsg;
    }
}
